package cn.chinaunicom.sdsi.frm.workflow.task.service.impl;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.task.Task;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import cn.chinaunicom.sdsi.frm.workflow.bean.BaseTaskVO;
import cn.chinaunicom.sdsi.frm.workflow.bean.HistoicFlowVO;
import cn.chinaunicom.sdsi.frm.workflow.bean.ProcInstInfo;
import cn.chinaunicom.sdsi.frm.workflow.bean.TaskVO;
import cn.chinaunicom.sdsi.frm.workflow.common.UtilDateTime;
import cn.chinaunicom.sdsi.frm.workflow.common.WorkflowConstants;
import cn.chinaunicom.sdsi.frm.workflow.component.WorkflowManager;
import cn.chinaunicom.sdsi.frm.workflow.ext.StaffBaseInfo;
import cn.chinaunicom.sdsi.frm.workflow.task.dao.ActTaskDao;
import cn.chinaunicom.sdsi.frm.workflow.task.dao.ActTaskHistDao;
import cn.chinaunicom.sdsi.frm.workflow.task.dao.FlowCfgDao;
import cn.chinaunicom.sdsi.frm.workflow.task.service.ActTaskService;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

/**
 * 工作流任务模块服务组件
 * 
 * @author liyh
 */
@Service("actTaskService")
public class ActTaskServiceImpl implements ActTaskService {

	private static final Log log = LogFactory.getLog(ActTaskServiceImpl.class);
	/**
	 * 工作流封装组件
	 */
	private WorkflowManager workflowManager;
	/**
	 * 工作流辅助配置访问组件
	 */
	private FlowCfgDao flowCfgDao;
	/**
	 * 任务数据访问层组件
	 */
	private ActTaskDao actTaskDao;
	/**
	 * 已办任务数据访问层组件
	 */
	private ActTaskHistDao actTaskHistDao;

	/**
	 * 业务系统实现的人员信息抽取接口
	 */
	private StaffBaseInfo staffBaseInfo;

	/**
	 * 查询符合分页条件的结果集
	 * 
	 * @param vo
	 *            查询条件封装
	 * @param firstResult
	 *            开始记录index
	 * @param maxResults
	 *            每页显示条数
	 * @return 返回的json对象
	 */
	@Override
	public JSONObject listToDo4Page(TaskVO vo, int firstResult, int maxResults) {
		/*
		 * 获取分页的结果集
		 */
		List<Task> taskList = actTaskDao.listToDo4Page(vo, firstResult, maxResults);
		/*
		 * 获取查询结果的总条数及符合记录条数
		 */
		long filteredCount = actTaskDao.listFilteredCount(vo);

		JSONArray array = new JSONArray();
		JSONObject obj = null;

		for (Task task : taskList) {

			obj = new JSONObject();

			String taskId = task.getId();
			// 获取流程实例变量及流程类型信息
			String title = (String) actTaskDao.parseVariable(task, "title");
			ProcInstInfo pii = workflowManager.getProcInstInfo(task.getProcessInstanceId());
			// 发起人userId
			String applyUserId = String.valueOf(actTaskDao.parseVariable(task, "applyUserId"));

			// 任务ID
			obj.element("id", taskId);
			// 环节名称
			obj.element("name", task.getName());
			// 流程标题
			obj.element("title", title);
			// 流程类型名称及键值
			obj.element("processDefinitionKey", pii.getProcessDefinitionKey());
			obj.element("processDefinitionName", pii.getProcessDefinitionName());
			// 流程申请人
			obj.element("applyUserId", applyUserId);
			// 受理人岗位ID及对应部门名称
			obj.element("assignee", task.getAssignee());
			obj.element("staffOrgName", staffBaseInfo.getStaffOrgName(task.getAssignee()));
			// 环节Key
			obj.element("taskDefinitionKey", task.getTaskDefinitionKey());
			// 任务创建时间
			obj.element("createTime", UtilDateTime.format2YMDHMS(task.getCreateTime()));
			// 流程实例ID
			obj.element("processInstanceId", task.getProcessInstanceId());
			// 流程定义ID
			obj.element("processDefinitionId", task.getProcessDefinitionId());
			// 执行流ID
			obj.element("executionId", task.getExecutionId());

			// 装配任务相关信息，剩余信息需要根据实际的业务系统的需要进行参数的设置
			array.add(obj);
		}
		log.debug("search task change to json done");

		obj = new JSONObject();
		obj.element("data", array);
		obj.element("recordsFiltered", filteredCount);
		obj.element("recordsTotal", filteredCount);
		obj.element("draw", 0);

		log.debug("search Task data done");

		return obj;
	}

	/**
	 * 查询符合分页条件的结果集
	 * 
	 * @param vo
	 *            任务对象
	 * @param firstResult
	 *            开始记录
	 * @param maxResults
	 *            每页条数
	 * @return 返回的json对象
	 */
	@Override
	public JSONObject listHasDone4Page(TaskVO vo, int firstResult, int maxResults) {
		/*
		 * 获取分页的结果集
		 */
		List<HistoricTaskInstance> taskList = actTaskHistDao.listHasDone4Page(vo, firstResult, maxResults);
		/*
		 * 获取查询结果的总条数及符合记录条数
		 */
		long filteredCount = actTaskHistDao.listFilteredCount(vo);

		JSONArray array = new JSONArray();
		JSONObject obj = null;

		for (HistoricTaskInstance task : taskList) {

			obj = new JSONObject();

			// 获取流程标题
			String title = (String) actTaskHistDao.parseVariable(task, "title");

			ProcInstInfo pii = workflowManager.getProcInstInfo(task.getProcessInstanceId());
			// 发起人userId
			String applyUserId = String.valueOf(actTaskHistDao.parseVariable(task, "applyUserId"));

			// 历史任务ID
			obj.element("id", task.getId());
			// 已办环节名称
			obj.element("name", task.getName());
			// 流程标题
			obj.element("title", title);
			// 流程类型名称及键值
			obj.element("processDefinitionKey", pii.getProcessDefinitionKey());
			obj.element("processDefinitionName", pii.getProcessDefinitionName());
			// 流程申请人
			obj.element("applyUserId", applyUserId);
			// 受理人岗位ID及对应部门名称
			obj.element("assignee", task.getAssignee());
			obj.element("staffOrgName", staffBaseInfo.getStaffOrgName(task.getAssignee()));
			// 环节Key
			obj.element("taskDefinitionKey", task.getTaskDefinitionKey());
			// 任务到达时间及完成时间
			obj.element("startTime", UtilDateTime.format2YMDHMS(task.getStartTime()));
			obj.element("endTime", UtilDateTime.format2YMDHMS(task.getEndTime()));
			// 流程实例ID
			obj.element("processInstanceId", task.getProcessInstanceId());
			// 流程定义ID
			obj.element("processDefinitionId", task.getProcessDefinitionId());
			// 执行流ID
			obj.element("executionId", task.getExecutionId());

			// 装配任务相关信息，剩余信息需要根据实际的业务系统的需要进行参数的设置
			array.add(obj);
		}
		log.debug("search Task change to json done");

		obj = new JSONObject();
		obj.element("data", array);
		obj.element("recordsFiltered", filteredCount);
		obj.element("recordsTotal", filteredCount);
		obj.element("draw", 0);

		log.debug("search Task data done");

		return obj;
	}

	/**
	 * 简退-回退操作
	 * 
	 * @param processInstanceId
	 *            流程实例ID
	 * @param taskId
	 *            当前任务ID
	 * @param comment
	 *            流程意见
	 * @return 是否成功
	 */
	@Override
	public boolean backForQuick(String processInstanceId, String taskId, String comment) {

		return workflowManager.backForQuick(processInstanceId, taskId, comment);
	}

	/**
	 * 简退-推进操作
	 * 
	 * @param processInstanceId
	 *            流程实例ID
	 * @param currentTaskId
	 *            当前进行简退推进操作的任务ID
	 * @param comment
	 *            推进意见
	 * @return 是否推进成功
	 */
	@Override
	public boolean pushForQuick(String processInstanceId, String currentTaskId, String comment) {

		return workflowManager.pushForQuick(processInstanceId, currentTaskId, comment);
	}

	/**
	 * 转派功能，当前任务更换处理人，记录流转历史
	 * 
	 * @param taskId
	 *            当前任务ID
	 * @param processInstanceId
	 *            流程实例ID
	 * @param assignee
	 *            预指定处理人
	 * @param comment
	 *            审批意见
	 * @return 新任务ID
	 */
	@Override
	public String transferTask(String taskId, String processInstanceId, String assignee, String comment) {

		return workflowManager.turnAssignee(taskId, processInstanceId, assignee, comment);
	}

	/**
	 * 根据待办、已办列表的参数获取主业务页面的URL
	 * 
	 * @param processInstanceId
	 *            流程实例ID
	 * @param taskId
	 *            任务ID
	 * @param taskDefinitionKey
	 *            流程定义key
	 * @param todo
	 *            是否待办，否则已办
	 * @return 待办业务处理路径相关信息
	 */
	@Override
	public JSONObject findTaskUrlAndHandleParam(String processInstanceId, String taskId, String taskDefinitionKey,
			boolean todo) {

		ProcInstInfo pii = workflowManager.getProcInstInfo(processInstanceId);
		/*
		 * 创建返回的JSON对象并进行数据包装
		 */
		JSONObject obj = new JSONObject();

		/*
		 * 获取流程编码组装路径
		 */
		Map<String, Object> map = flowCfgDao.getTaskCustomUrl(pii.getProcessDefinitionId(),
				pii.getProcessDefinitionKey(), taskDefinitionKey, todo);
		if (map == null) {
			return null;
		}
		String uniUrl = String.valueOf(map.get("URL"));
		if ("".equals(uniUrl)) {
			return null;
		}
		String businessKey = pii.getBusinessKey();
		/*
		 * 组装业务处理路径
		 */
		StringBuilder sb = new StringBuilder(uniUrl);
		sb.append("?businessKey=").append(businessKey).append("&processInstanceId=").append(processInstanceId)
				.append("&taskDefinitionKey=").append(taskDefinitionKey).append("&taskId=").append(taskId);

		boolean startLink = this.isStartLink(map);
		sb.append("&startLink=").append(startLink);
		obj.element("startLink", startLink);

		boolean endLink = false;
		if (!startLink) {
			endLink = this.isEndLink(map);
		}
		sb.append("&endLink=").append(endLink);
		obj.element("endLink", endLink);

		obj.element("url", sb.toString());

		return obj;
	}

	/**
	 * 判断是否为首环节
	 * 
	 * @param map
	 * @return 是否发起环节
	 */
	private boolean isStartLink(Map<String, Object> map) {

		boolean startLink = false;
		int linkFlag = Integer.parseInt(String.valueOf(map.get("LINK_FLAG")));
		if (WorkflowConstants.LINK_FLAG_START == linkFlag) {
			startLink = true;
		}

		return startLink;
	}

	/**
	 * 判断是否为尾环节
	 * 
	 * @param map
	 * @return 是否末尾环节
	 */
	private boolean isEndLink(Map<String, Object> map) {

		boolean endLink = false;
		int linkFlag = Integer.parseInt(String.valueOf(map.get("LINK_FLAG")));
		if (WorkflowConstants.LINK_FLAG_END == linkFlag) {
			endLink = true;
		}

		return endLink;
	}

	/**
	 * 获取流程图
	 * 
	 * @param processInstanceId
	 *            流程实例ID
	 * @return
	 * @throws Exception
	 */
	@Override
	public byte[] getDiagram(String processInstanceId) throws Exception {

		byte[] bs = this.getImgByte(workflowManager.getDiagramInputStream(processInstanceId));
		// .getDiagramInputStreamForHistory(processInstanceId));

		return bs;
	}

	/**
	 * 输入流转byte数组
	 * 
	 * @param is
	 * @return
	 * @throws IOException
	 */
	private byte[] getImgByte(InputStream is) throws IOException {

		ByteArrayOutputStream bytestream = new ByteArrayOutputStream();
		int b;
		while ((b = is.read()) != -1) {
			bytestream.write(b);
		}
		byte[] bs = bytestream.toByteArray();
		bytestream.close();

		return bs;
	}

	/**
	 * 根据流程定义及任务定义与审批状况查找可选环节
	 * 
	 * @param processDefinitionKey
	 *            流程定义Key
	 * @param pathSelect
	 *            分支环节选取环节
	 * @return 包含可选路径的组合对象
	 */
	@Override
	public JSONArray findLinkIds(String processDefinitionKey, int pathSelect) {

		// 获取流程编码对应的最新定义信息主键
		String processDefinitionId = workflowManager.convertToDefinitionId(processDefinitionKey);
		String taskDefinitionKey = flowCfgDao.getStartTaskKey(processDefinitionId, processDefinitionKey);

		return parseLinkInfo(processDefinitionId, processDefinitionKey, taskDefinitionKey, 1, pathSelect);
	}

	/**
	 * 用户审批点击通过或回退时加载可选环节
	 * 
	 * @param taskId
	 *            当前任务ID
	 * @param handleType
	 *            处理类型（1、通过2、退回）
	 * @param passSelect
	 *            分支环节选取环节
	 * @return 可选环节键值对
	 */
	@Override
	public JSONArray findLinkIds(String taskId, int handleType, int pathSelect) {

		// 获取任务对应的实例定义信息及任务定义信息
		BaseTaskVO bto = workflowManager.getBaseTaskVO(taskId);
		String processDefinitionId = bto.getProcessDefinitionId();
		String processDefinitionKey = bto.getProcessDefinitionKey();
		String taskDefinitionKey = bto.getTaskDefinitionKey();

		return parseLinkInfo(processDefinitionId, processDefinitionKey, taskDefinitionKey, handleType, pathSelect);
	}

	/**
	 * 据传入条件获取可达环节集合信息
	 * 
	 * @param processDefinitionId
	 *            流程定义信息主键
	 * @param processDefinitionKey
	 *            流程定义Key
	 * @param taskDefinitionKey
	 *            环节定义Key
	 * @param handleType
	 *            流转方式
	 * @param pathSelect
	 *            路径选择变量
	 * @return 可选环节键值对
	 */
	private JSONArray parseLinkInfo(String processDefinitionId, String processDefinitionKey, String taskDefinitionKey,
			int handleType, int pathSelect) {

		List<Map<String, Object>> list = flowCfgDao.getLinkIds(processDefinitionId, processDefinitionKey,
				taskDefinitionKey, pathSelect, handleType);

		JSONArray array = new JSONArray();
		JSONObject obj = null;
		for (Map<String, Object> map : list) {

			obj = new JSONObject();
			String linkKey = (String) map.get("LINK_KEY");
			String linkName = (String) map.get("LINK_NAME");
			// 默认不可撤回
			int withdraw = Integer.parseInt(String.valueOf(map.get("WITHDRAW")));

			// 若可到达结束节点，需做特殊处理
			String linkId = (String) map.get("LINK_ID");
			if (!"".equals(linkId) && StringUtils.isBlank(linkKey)) {
				linkKey = linkId;
				linkId = "END";
				linkName = "END";
				withdraw = 0;
			}

			obj.element("label", linkName);
			obj.element("value", linkKey + "," + withdraw + "," + linkId);
			array.add(obj);
		}

		return array;
	}

	/**
	 * 获取办理信息tab页集合
	 * 
	 * @param processDefinitionId
	 *            流程定义数据主键
	 * @param taskDefinitionKey
	 *            任务定义KEY
	 * @param todo
	 *            是否为待办
	 * @return 返回集合数据信息
	 */
	@Override
	public JSONArray parseTabUrls(String processDefinitionId, String taskDefinitionKey, boolean todo) {

		JSONArray array = new JSONArray();
		// 获取查询结果，再根据查询待办或已办筛选
		List<Map<String, Object>> list = flowCfgDao.getTabUrls(processDefinitionId, taskDefinitionKey);
		if (list == null || list.size() == 0) {
			return array;
		}

		// 待办筛选掉类型3，已办筛选掉类型2
		int remove = 0;
		if (todo) {
			remove = WorkflowConstants.TAB_HASDONE_DISPLAY;
		} else {
			remove = WorkflowConstants.TAB_TODO_DISPLAY;
		}

		JSONObject obj = null;
		// 循环组装结果集
		for (int i = 0; i < list.size(); i++) {

			obj = new JSONObject();
			Map<String, Object> map = list.get(i);
			int type = Integer.parseInt(String.valueOf(map.get("TAB_FLAG")));

			if (type != remove) {
				String name = String.valueOf(map.get("NAME"));
				String url = String.valueOf(map.get("URL"));
				obj.element("name", name);
				obj.element("url", url);

				array.add(obj);
			}
		}

		return array;
	}

	/**
	 * 获取任务详细页面环节出行及按钮显隐配置
	 * 
	 * @param processDefinitionKey
	 *            流程定义Key
	 * @param taskDefinitionKey
	 *            任务定义Key
	 * @return 按钮显隐信息
	 */
	@Override
	public Map<String, Boolean> getLinkCfg(String processDefinitionKey, String taskDefinitionKey) {

		Map<String, Boolean> results = new HashMap<String, Boolean>();

		Map<String, Object> map = flowCfgDao.getLinkCfg(processDefinitionKey, taskDefinitionKey);
		if (map != null) {

			int buttonBack = Integer.parseInt(String.valueOf(map.get("BUTTON_BACK")));
			int buttonTurn = Integer.parseInt(String.valueOf(map.get("BUTTON_TURN")));
			int buttonBreak = Integer.parseInt(String.valueOf(map.get("BUTTON_BREAK")));
			int buttonQuick = Integer.parseInt(String.valueOf(map.get("BUTTON_QUICK")));
			int isCounterSign = Integer.parseInt(String.valueOf(map.get("IS_COUNTERSIGN")));
			results.put("buttonBack", buttonBack == 1 ? true : false);
			results.put("buttonTurn", buttonTurn == 1 ? true : false);
			results.put("buttonBreak", buttonBreak == 1 ? true : false);
			results.put("buttonQuick", buttonQuick == 1 ? true : false);
			// 是否是会签节点
			results.put("isCounterSign", isCounterSign == 1 ? true : false);

			return results;
		} else {
			return null;
		}
	}

	/**
	 * 据流程实例ID获取流转历史
	 * 
	 * @param procInsId
	 *            流程实例ID
	 * @return 时间顺序流程全部流转记录集合
	 */
	@Override
	public List<HistoicFlowVO> findHistoicFlowList(String procInsId) {

		return workflowManager.histoicFlowList(procInsId);
	}

	/**
	 * 浏览待办后，为上环节处理人不可撤回打标
	 * 
	 * @param processInstanceId
	 *            实例ID
	 * @param taskId
	 *            任务ID
	 * @return 更新记录数，正常为1
	 */
	@Override
	public int viewTask(String processInstanceId, String taskId) {

		return workflowManager.signTask(processInstanceId, taskId);
	}

	/**
	 * 判断当前已办环节是否可以撤回
	 * 
	 * @param processInstanceId
	 *            实例
	 * @param taskId
	 *            任务
	 * @return 是否可回撤
	 */
	@Override
	public boolean isCanWithDraw(String processInstanceId, String taskId) {

		return workflowManager.isCanWithDraw(processInstanceId, taskId);
	}

	/**
	 * 是否为简退后的提交首环节
	 * 
	 * @param processInstanceId
	 *            流程实例ID
	 * @param taskId
	 *            任务ID
	 * @return 是否可直接提交至退回环节的退回人
	 */
	@Override
	public boolean isBackForQuick(String processInstanceId, String taskId) {

		return workflowManager.isBackForQuick(processInstanceId, taskId);
	}

	/**
	 * 查看任务是否已经完成
	 * 
	 * @param taskId
	 *            任务ID
	 * @return 是否已经完成
	 */
	@Override
	public boolean isFinishedTask(String taskId) {

		return workflowManager.isFinishedTask(taskId);
	}

	@Autowired
	public void setWorkflowManager(WorkflowManager workflowManager) {
		this.workflowManager = workflowManager;
	}

	@Autowired
	public void setFlowCfgDao(FlowCfgDao flowCfgDao) {
		this.flowCfgDao = flowCfgDao;
	}

	@Autowired
	public void setActTaskDao(@Qualifier("actTaskNativeDao") ActTaskDao actTaskDao) {
		this.actTaskDao = actTaskDao;
	}

	@Autowired
	public void setActTaskHistDao(@Qualifier("actTaskHistNativeDao") ActTaskHistDao actTaskHistDao) {
		this.actTaskHistDao = actTaskHistDao;
	}

	@Autowired
	public void setStaffBaseInfo(StaffBaseInfo staffBaseInfo) {
		this.staffBaseInfo = staffBaseInfo;
	}

}
